在 Cargo.toml 補上:
tower-http = { version = "0.6", features = ["cors", "trace"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }
http = "1.3"
在 main.rs 新增的 imports 與中間件設定:
新增 imports(在檔案頂端):
use tower_http::cors::{CorsLayer, Any, AllowOrigin};
use tower_http::trace::{TraceLayer, DefaultMakeSpan, DefaultOnResponse};
use tracing_subscriber::{EnvFilter, fmt};
use tracing::Level;
use http::{Method, HeaderValue};
use tracing_subscriber::prelude::*;
在 main 加入 tracing 初始化(放在 dotenv().ok() 之後):
let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
tracing_subscriber::registry()
.with(env_filter)
.with(fmt::layer().with_target(false)) // 或 .json() 輸出 JSON
.init();
建立 CorsLayer 與 TraceLayer:
let localhost = HeaderValue::from_static("http://localhost:5173");
let cors = CorsLayer::new()
.allow_origin(AllowOrigin::exact(localhost))
.allow_methods([Method::GET, Method::POST, Method::PUT, Method::DELETE, Method::OPTIONS])
.allow_headers(Any)
.max_age(std::time::Duration::from_secs(600));
let trace = TraceLayer::new_for_http()
.make_span_with(DefaultMakeSpan::new().include_headers(false)) // 不自動包含 headers,避免敏感資訊
.on_response(DefaultOnResponse::new().level(Level::INFO));
把 layer 套到 Router:
let app = Router::new()
// ...
.layer(trace)
.layer(cors)
.layer(Extension(pool))
.layer(Extension(redis_conn));
備註
在 .env 加入:
RUST_LOG=debug
開啟詳細DEBUG紀錄
OPTIONS http://127.0.0.1:3000/users
HTTP/1.1 200 OK
vary: origin, access-control-request-method, access-control-request-headers
access-control-allow-methods: GET,POST,PUT,DELETE,OPTIONS
access-control-allow-headers: *
access-control-max-age: 600
access-control-allow-origin: http://localhost:5173
allow: POST,GET,HEAD
content-length: 0
date: Sun, 05 Oct 2025 00:56:25 GMT
檢查回應是否有 Access-Control-Allow-Origin / Allow-Methods
重點結論